using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Model;
using Me.Prettyprint.Cassandra.Model.Thrift;
using Me.Prettyprint.Cassandra.Service;
using Me.Prettyprint.Hector.Api;
using Me.Prettyprint.Hector.Api.Factory;
using Me.Prettyprint.Hector.Api.Mutation;
using Org.Apache.Cassandra.Thrift;
using Thrift;

namespace Me.Prettyprint.Cassandra.Service.Template
{
    /// <summary>
    /// By default, the ConsistencyLevelPolicy is set to QuoromAllConsistencyLevelPolicy. If you want
    /// the consistency level to be more relaxed, change it to eitehr AllOneConsistencyLevelPolicy
    /// or ConfigurableConsistencyLevel in the ColumnFamilyUpdater instead. Setting the consistency
    /// level in the ColumnFamilyTemplate isn't thread safe as described in Hector's javadoc.
    /// </summary>
    /// <typeparam name="K"></typeparam>
    /// <typeparam name="N"></typeparam>
    public class AbstractColumnFamilyTemplate<K, N>
	{
        /// <summary>
        /// This is used when we want all the columns
        /// </summary>
        public const int ALL_COLUMNS_COUNT = int.MaxValue;
        public const object ALL_COLUMNS_START = null;
        public const object ALL_COLUMNS_END = null;

		public AbstractColumnFamilyTemplate()
		{
            ConsistencyLevelPolicy = new QuorumAllConsistencyLevelPolicy();
        }
        public AbstractColumnFamilyTemplate(Keyspace keyspace, String columnFamily,
            Serializer<K> keySerializer, Serializer<N> topSerializer) : base()
        {
            Keyspace = keyspace;
            ColumnFamily = columnFamily;
            KeySerializer = keySerializer;
            TopSerializer = topSerializer;
            ColumnValueSerializers = new Dictionary<N, Serializer<object>>();
            ColumnParent = new Org.Apache.Cassandra.Thrift.ColumnParent(columnFamily);
            ActiveSlicePredicate = new HSlicePredicate<N>(topSerializer);
            ExceptionsTranslator = new ExceptionsTranslatorImpl();
            ColumnFactory = new ThriftColumnFactory();
            ConsistencyLevelPolicy = keyspace.ConsistencyLevelPolicy;
            SetCount(100);
        }
        /// <summary>
        /// Get will call Keyspace.CreateClock();
        /// </summary>
        public long Clock
        {
            get
            {
                return Keyspace.CreateClock();
            }
        }
        public bool Batched
        {
            get;
            set;
        }
        public ExceptionsTranslator ExceptionsTranslator
        {
            get;set;
        }
        /// <summary>
        /// Serializer for the standard column name or super column name
        /// </summary>
        public Serializer<N> TopSerializer
        {
            get;
            private set;
        }
        public ColumnFactory ColumnFactory
        {
            get;
            set;
        }
        public string ColumnFamily
        {
            get;
            private set;
        }
        public ConsistencyLevelPolicy ConsistencyLevelPolicy
        {
            get;
            private set;
        }
        public HSlicePredicate<N> ActiveSlicePredicate
        {
            get;
            private set;
        }
        public ColumnParent ColumnParent
        {
            get;
            set;
        }
        public Keyspace Keyspace
        {
            get;
            set;
        }
        public Dictionary<N, Serializer<object>> ColumnValueSerializers
        {
            get;
            set;
        }
        public Serializer<K> KeySerializer
        {
            get;
            set;
        }
        public void SetCount(int count)
        {
            ActiveSlicePredicate.SetCount(count);
        }
        public AbstractColumnFamilyTemplate<K,N> AddColumn(N columnName, Serializer<object> valueSerializer)
        {
            ColumnValueSerializers[columnName] = valueSerializer;
            ActiveSlicePredicate.AddColumnName(columnName);
            return this;
        }
        public Serializer<object> GetValueSerializer(N columnName)
        {
            return ColumnValueSerializers[columnName];
        }
        public AbstractColumnFamilyTemplate<K, N> SetBatched(bool batched)
        {
            Batched = batched;
            return this;
        }
        public MutationResult ExecuteBatch(Mutator<K> mutator)
        {
            MutationResult result = mutator.Execute();
            mutator.DiscardPendingMutations();
            return result;
        }
        public Mutator<K> CreateMutator()
        {
            return HFactory.CreateMutator(Keyspace, KeySerializer);
        }
        protected MutationResult ExecuteIfNotBatched(Mutator<K> mutator)
        {
            return !Batched ? ExecuteBatch(mutator) : null;
        }
        protected MutationResult ExecuteIfNotBatched(AbstractTemplateUpdater<K, N> updater)
        {
            return !Batched ? ExecuteBatch(updater.CurrentMutator) : null;
        }
        public void deleteRow(K key)
        {
            CreateMutator().AddDeletion(key, ColumnFamily, default(N), TopSerializer).Execute();
        }
        public void DeleteRow(Mutator<K> mutator, K key)
        {
            mutator.AddDeletion(key, ColumnFamily, default(N), TopSerializer);
            ExecuteIfNotBatched(mutator);
        }
        public void DeleteColumn(K key, N columnName)
        {
            CreateMutator().AddDeletion(key, ColumnFamily, columnName, TopSerializer).Execute();
        }
        public void DeleteColumn(Mutator<K> mutator, K key, N columnName)
        {
            mutator.AddDeletion(key, ColumnFamily, columnName, TopSerializer);
            ExecuteIfNotBatched(mutator);
        }
	}
}